Pythonã®ãã¹ã¯ãªãã¿ãããã³ã«ããã¹ã¿ãŒããå ç¢ãªããããã£ã¢ã¯ã»ã¹å¶åŸ¡ãé«åºŠãªããŒã¿æ€èšŒãå®çŸããããã¯ãªãŒã³ã§ä¿å®æ§ã®é«ãã³ãŒããäœæããŸããå®è·µçãªäŸãšãã¹ããã©ã¯ãã£ã¹ãå«ã¿ãŸãã
Pythonãã¹ã¯ãªãã¿ãããã³ã«ïŒããããã£ã¢ã¯ã»ã¹å¶åŸ¡ãšããŒã¿æ€èšŒããã¹ã¿ãŒãã
Pythonã®ãã¹ã¯ãªãã¿ãããã³ã«ã¯ãã¯ã©ã¹å ã®å±æ§ã¢ã¯ã»ã¹ãšå€æŽããã现ããå¶åŸ¡ã§ããã匷åã§ãããªãããã°ãã°ååã«æŽ»çšãããŠããªãæ©èœã§ããããã«ãããé«åºŠãªããŒã¿æ€èšŒãšããããã£ç®¡çãå®è£ ããæ¹æ³ãæäŸãããããã¯ãªãŒã³ã§å ç¢ããã€ä¿å®æ§ã®é«ãã³ãŒããå®çŸããŸãããã®å æ¬çãªã¬ã€ãã§ã¯ããã¹ã¯ãªãã¿ãããã³ã«ã®è€éããæãäžãããã®äžå¿çãªæŠå¿µãå®è·µçãªå¿çšããã¹ããã©ã¯ãã£ã¹ãæ¢ããŸãã
ãã¹ã¯ãªãã¿ãçè§£ãã
æ žå¿éšåãšããŠããã¹ã¯ãªãã¿ãããã³ã«ã¯ã屿§ããã¹ã¯ãªãã¿ãšåŒã°ããç¹æ®ãªã¿ã€ãã®ãªããžã§ã¯ãã§ããå Žåã«ã屿§ã¢ã¯ã»ã¹ãã©ã®ããã«åŠçãããããå®çŸ©ããŸãããã¹ã¯ãªãã¿ã¯ã以äžã®ã¡ãœããã®1ã€ä»¥äžãå®è£ ããã¯ã©ã¹ã§ãïŒ
- `__get__(self, instance, owner)`: ãã¹ã¯ãªãã¿ã®å€ãã¢ã¯ã»ã¹ããããšãã«åŒã³åºãããŸãã
- `__set__(self, instance, value)`: ãã¹ã¯ãªãã¿ã®å€ãèšå®ããããšãã«åŒã³åºãããŸãã
- `__delete__(self, instance)`: ãã¹ã¯ãªãã¿ã®å€ãåé€ããããšãã«åŒã³åºãããŸãã
ã¯ã©ã¹ã€ã³ã¹ã¿ã³ã¹ã®å±æ§ããã¹ã¯ãªãã¿ã§ããå ŽåãPythonã¯åºã«ãªã屿§ã«çŽæ¥ã¢ã¯ã»ã¹ãã代ããã«ããããã®ã¡ãœãããèªåçã«åŒã³åºããŸãããã®ã€ã³ã¿ãŒã»ããã¡ã«ããºã ããããããã£ã¢ã¯ã»ã¹å¶åŸ¡ãšããŒã¿æ€èšŒã®åºç€ãæäŸããŸãã
ããŒã¿ãã¹ã¯ãªãã¿ vs. éããŒã¿ãã¹ã¯ãªãã¿
ãã¹ã¯ãªãã¿ã¯ããã«2ã€ã®ã«ããŽãªã«åé¡ãããŸãïŒ
- ããŒã¿ãã¹ã¯ãªãã¿: `__get__` ãš `__set__` ã®äž¡æ¹ïŒããã³ãªãã·ã§ã³ã§ `__delete__`ïŒãå®è£ ããŸããåãååã®ã€ã³ã¹ã¿ã³ã¹å±æ§ãããé«ãåªå é äœãæã¡ãŸããããã¯ãããŒã¿ãã¹ã¯ãªãã¿ã§ãã屿§ã«ã¢ã¯ã»ã¹ãããšãã€ã³ã¹ã¿ã³ã¹ã«åãååã®å±æ§ããã£ãŠããåžžã«ãã¹ã¯ãªãã¿ã® `__get__` ã¡ãœãããåŒã³åºãããããšãæå³ããŸãã
- éããŒã¿ãã¹ã¯ãªãã¿: `__get__` ã®ã¿ãå®è£ ããŸããã€ã³ã¹ã¿ã³ã¹å±æ§ãããäœãåªå é äœãæã¡ãŸããã€ã³ã¹ã¿ã³ã¹ã«åãååã®å±æ§ãããå Žåããã¹ã¯ãªãã¿ã® `__get__` ã¡ãœãããåŒã³åºã代ããã«ããã®å±æ§ãè¿ãããŸããããã«ãããèªã¿åãå°çšããããã£ã®å®è£ ãªã©ã«åœ¹ç«ã¡ãŸãã
éèŠãªéã㯠`__set__` ã¡ãœããã®ååšã«ãããŸããããããªãå Žåããã¹ã¯ãªãã¿ã¯éããŒã¿ãã¹ã¯ãªãã¿ã«ãªããŸãã
ãã¹ã¯ãªãã¿äœ¿çšã®å®è·µäŸ
ãã¹ã¯ãªãã¿ã®åãããã€ãã®å®è·µçãªäŸã§ç€ºããŸãããã
äŸ1ïŒåãã§ãã¯
ç¹å®ã®å±æ§ãåžžã«ç¹å®ã®åã®å€ãä¿æããããã«ããããšããŸãããã¹ã¯ãªãã¿ã¯ãã®åå¶çŽã匷å¶ã§ããŸãïŒ
class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
if instance is None:
return self # ã¯ã©ã¹èªäœããã®ã¢ã¯ã»ã¹
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"Expected {self.expected_type}, got {type(value)}")
instance.__dict__[self.name] = value
class Person:
name = Typed('name', str)
age = Typed('age', int)
def __init__(self, name, age):
self.name = name
self.age = age
# äœ¿çšæ³:
person = Person("Alice", 30)
print(person.name) # åºå: Alice
print(person.age) # åºå: 30
try:
person.age = "thirty"
except TypeError as e:
print(e) # åºå: Expected <class 'int'>, got <class 'str'>
ãã®äŸã§ã¯ã`Typed` ãã¹ã¯ãªãã¿ã `Person` ã¯ã©ã¹ã® `name` ããã³ `age` 屿§ã®åãã§ãã¯ã匷å¶ããŸããééã£ãåã®å€ãä»£å ¥ããããšãããš `TypeError` ãçºçããŸããããã«ãããããŒã¿ã®æŽåæ§ãåäžããã³ãŒãã®åŸåã§äºæããªããšã©ãŒãé²ãããšãã§ããŸãã
äŸ2ïŒããŒã¿æ€èšŒ
åãã§ãã¯ä»¥å€ã«ãããã¹ã¯ãªãã¿ã¯ããè€éãªããŒã¿æ€èšŒãå®è¡ã§ããŸããäŸãã°ãæ°å€ãç¹å®ã®ç¯å²å ã«ããããšã確èªãããå ŽåããããŸãïŒ
class Sized:
def __init__(self, name, min_value, max_value):
self.name = name
self.min_value = min_value
self.max_value = max_value
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, (int, float)):
raise TypeError("Value must be a number")
if not (self.min_value <= value <= self.max_value):
raise ValueError(f"Value must be between {self.min_value} and {self.max_value}")
instance.__dict__[self.name] = value
class Product:
price = Sized('price', 0, 1000)
def __init__(self, price):
self.price = price
# äœ¿çšæ³:
product = Product(99.99)
print(product.price) # åºå: 99.99
try:
product.price = -10
except ValueError as e:
print(e) # åºå: Value must be between 0 and 1000
ããã§ã¯ã`Sized` ãã¹ã¯ãªãã¿ã `Product` ã¯ã©ã¹ã® `price` 屿§ã0ãã1000ã®ç¯å²å ã®æ°å€ã§ããããšãæ€èšŒããŸããããã«ããã補åäŸ¡æ Œã劥åœãªç¯å²å ã«åãŸãããšãä¿èšŒãããŸãã
äŸ3ïŒèªã¿åãå°çšããããã£
éããŒã¿ãã¹ã¯ãªãã¿ã䜿çšããŠãèªã¿åãå°çšããããã£ãäœæã§ããŸãã`__get__` ã¡ãœããã®ã¿ãå®çŸ©ããããšã§ããŠãŒã¶ãŒã屿§ãçŽæ¥å€æŽããã®ãé²ããŸãïŒ
class ReadOnly:
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if instance is None:
return self
return instance._private_value # ãã©ã€ããŒã屿§ã«ã¢ã¯ã»ã¹
class Circle:
radius = ReadOnly('radius')
def __init__(self, radius):
self._private_value = radius # ãã©ã€ããŒã屿§ã«å€ãä¿å
# äœ¿çšæ³:
circle = Circle(5)
print(circle.radius) # åºå: 5
try:
circle.radius = 10 # ããã«ãã*æ°ãã*ã€ã³ã¹ã¿ã³ã¹å±æ§ãäœæãããŸãïŒ
print(circle.radius) # åºå: 10
print(circle.__dict__) # åºå: {'_private_value': 5, 'radius': 10}
except AttributeError as e:
print(e) # æ°ããã€ã³ã¹ã¿ã³ã¹å±æ§ããã¹ã¯ãªãã¿ãã·ã£ããŠã€ã³ã°ãããããããã¯ããªã¬ãŒãããŸããã
ãã®ã·ããªãªã§ã¯ã`ReadOnly` ãã¹ã¯ãªãã¿ã `Circle` ã¯ã©ã¹ã® `radius` 屿§ãèªã¿åãå°çšã«ããŸãã`circle.radius` ãžã®çŽæ¥ä»£å ¥ã¯ãšã©ãŒãçºçãããã代ããã«ãã¹ã¯ãªãã¿ãã·ã£ããŠã€ã³ã°ããæ°ããã€ã³ã¹ã¿ã³ã¹å±æ§ãäœæããããšã«æ³šæããŠãã ãããä»£å ¥ãæ¬åœã«é²ãã«ã¯ã`__set__` ãå®è£ ã㊠`AttributeError` ãçºçãããå¿ èŠããããŸãããã®äŸã¯ãããŒã¿ãã¹ã¯ãªãã¿ãšéããŒã¿ãã¹ã¯ãªãã¿ã®åŸ®åŠãªéããšãåŸè ã§ã·ã£ããŠã€ã³ã°ãçºçããä»çµã¿ã瀺ããŠããŸãã
äŸ4ïŒé å»¶èšç®ïŒé å»¶è©äŸ¡ïŒ
ãã¹ã¯ãªãã¿ã¯ãå€ãæåã«ã¢ã¯ã»ã¹ããããšãã«ã®ã¿èšç®ãããé å»¶è©äŸ¡ãå®è£ ããããã«ã䜿çšã§ããŸãïŒ
import time
class LazyProperty:
def __init__(self, func):
self.func = func
self.name = func.__name__
def __get__(self, instance, owner):
if instance is None:
return self
value = self.func(instance)
instance.__dict__[self.name] = value # çµæããã£ãã·ã¥ãã
return value
class DataProcessor:
@LazyProperty
def expensive_data(self):
print("Calculating expensive data...")
time.sleep(2) # æéã®ãããèšç®ãã·ãã¥ã¬ãŒã
return [i for i in range(1000000)]
# äœ¿çšæ³:
processor = DataProcessor()
print("Accessing data for the first time...")
start_time = time.time()
data = processor.expensive_data # ãããèšç®ãããªã¬ãŒããŸã
end_time = time.time()
print(f"Time taken for first access: {end_time - start_time:.2f} seconds")
print("Accessing data again...")
start_time = time.time()
data = processor.expensive_data # ããã¯ãã£ãã·ã¥ãããå€ã䜿çšããŸã
end_time = time.time()
print(f"Time taken for second access: {end_time - start_time:.2f} seconds")
`LazyProperty` ãã¹ã¯ãªãã¿ã¯ `expensive_data` ã®èšç®ãæåã«ã¢ã¯ã»ã¹ããããŸã§é å»¶ãããŸãããã®åŸã®ã¢ã¯ã»ã¹ã§ã¯ãã£ãã·ã¥ãããçµæãååŸãããããã©ãŒãã³ã¹ãåäžããŸãããã®ãã¿ãŒã³ã¯ãèšç®ã«å€ãã®ãªãœãŒã¹ãå¿ èŠãšããåžžã«å¿ èŠãšã¯éããªã屿§ã«åœ¹ç«ã¡ãŸãã
é«åºŠãªãã¹ã¯ãªãã¿ãã¯ããã¯
åºæ¬çãªäŸãè¶ ããŠããã¹ã¯ãªãã¿ãããã³ã«ã¯ããé«åºŠãªå¯èœæ§ãæäŸããŸãïŒ
ãã¹ã¯ãªãã¿ã®çµã¿åãã
ãã¹ã¯ãªãã¿ãçµã¿åãããŠãããè€éãªããããã£ã®æ¯ãèããäœæã§ããŸããäŸãã°ã`Typed` ãã¹ã¯ãªãã¿ãš `Sized` ãã¹ã¯ãªãã¿ãçµã¿åãããŠã屿§ã«åãšç¯å²ã®äž¡æ¹ã®å¶çŽã匷å¶ããããšãã§ããŸãã
class ValidatedProperty:
def __init__(self, name, expected_type, min_value=None, max_value=None):
self.name = name
self.expected_type = expected_type
self.min_value = min_value
self.max_value = max_value
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"Expected {self.expected_type}, got {type(value)}")
if self.min_value is not None and value < self.min_value:
raise ValueError(f"Value must be at least {self.min_value}")
if self.max_value is not None and value > self.max_value:
raise ValueError(f"Value must be at most {self.max_value}")
instance.__dict__[self.name] = value
class Employee:
salary = ValidatedProperty('salary', int, min_value=0, max_value=1000000)
def __init__(self, salary):
self.salary = salary
# äŸ
employee = Employee(50000)
print(employee.salary)
try:
employee.salary = -1000
except ValueError as e:
print(e)
try:
employee.salary = "abc"
except TypeError as e:
print(e)
ã¡ã¿ã¯ã©ã¹ãšãã¹ã¯ãªãã¿ã®äœ¿çš
ã¡ã¿ã¯ã©ã¹ã䜿çšããŠãç¹å®ã®åºæºãæºããã¯ã©ã¹ã®ãã¹ãŠã®å±æ§ã«ãã¹ã¯ãªãã¿ãèªåçã«é©çšããããšãã§ããŸããããã«ãããå®åçãªã³ãŒããå€§å¹ ã«åæžããã¯ã©ã¹éã®äžè²«æ§ã確ä¿ã§ããŸãã
class DescriptorMetaclass(type):
def __new__(cls, name, bases, attrs):
for attr_name, attr_value in attrs.items():
if isinstance(attr_value, Descriptor):
attr_value.name = attr_name # 屿§åããã¹ã¯ãªãã¿ã«æ³šå
¥ãã
return super().__new__(cls, name, bases, attrs)
class Descriptor:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
class UpperCase(Descriptor):
def __set__(self, instance, value):
if not isinstance(value, str):
raise TypeError("Value must be a string")
instance.__dict__[self.name] = value.upper()
class MyClass(metaclass=DescriptorMetaclass):
name = UpperCase()
# 䜿çšäŸ:
obj = MyClass()
obj.name = "john doe"
print(obj.name) # åºå: JOHN DOE
ãã¹ã¯ãªãã¿ã䜿çšããããã®ãã¹ããã©ã¯ãã£ã¹
ãã¹ã¯ãªãã¿ãããã³ã«ã广çã«äœ¿çšããããã«ã以äžã®ãã¹ããã©ã¯ãã£ã¹ãèæ ®ããŠãã ããïŒ
- è€éãªããžãã¯ãæã€å±æ§ã®ç®¡çã«ãã¹ã¯ãªãã¿ã䜿çšããïŒ ãã¹ã¯ãªãã¿ã¯ãå¶çŽã匷å¶ããããèšç®ãå®è¡ãããã屿§ãžã®ã¢ã¯ã»ã¹ã倿޿ã«ã«ã¹ã¿ã ã®æ¯ãèããå®è£ ããå¿ èŠãããå Žåã«æã䟡å€ããããŸãã
- ãã¹ã¯ãªãã¿ãéäžãããåå©çšå¯èœã«ä¿ã€ïŒ ç¹å®ã®ã¿ã¹ã¯ãå®è¡ããããã«ãã¹ã¯ãªãã¿ãèšèšããè€æ°ã®ã¯ã©ã¹ã§åå©çšã§ããã»ã©æ±çšçã«ããŸãã
- åçŽãªã±ãŒã¹ã§ã¯ property() ãä»£æ¿æ¡ãšããŠæ€èšããïŒ çµã¿èŸŒã¿ã® `property()` 颿°ã¯ãåºæ¬çãªã²ãã¿ãŒãã»ãã¿ãŒãããªãŒã¿ã¡ãœãããå®è£ ããããã®ããç°¡åãªæ§æãæäŸããŸããããé«åºŠãªå¶åŸ¡ãåå©çšå¯èœãªããžãã¯ãå¿ èŠãªå Žåã«ãã¹ã¯ãªãã¿ã䜿çšããŸãã
- ããã©ãŒãã³ã¹ã«æ³šæããïŒ ãã¹ã¯ãªãã¿ã¢ã¯ã»ã¹ã¯ãçŽæ¥çãªå±æ§ã¢ã¯ã»ã¹ãšæ¯èŒããŠãªãŒããŒãããã远å ããå¯èœæ§ããããŸããã³ãŒãã®ããã©ãŒãã³ã¹ãéèŠãªã»ã¯ã·ã§ã³ã§ã®ãã¹ã¯ãªãã¿ã®é床ã®äœ¿çšã¯é¿ããŠãã ããã
- æç¢ºã§èª¬æçãªååã䜿çšããïŒ ãã¹ã¯ãªãã¿ã®ç®çãæç¢ºã«ç€ºãååãéžæããŸãã
- ãã¹ã¯ãªãã¿ã培åºçã«ææžåããïŒ åãã¹ã¯ãªãã¿ã®ç®çãšãããã屿§ã¢ã¯ã»ã¹ã«ã©ã®ããã«åœ±é¿ãããã説æããŸãã
ã°ããŒãã«ãªèæ ®äºé ãšåœéå
ã°ããŒãã«ãªã³ã³ããã¹ãã§ãã¹ã¯ãªãã¿ã䜿çšããå Žåã¯ã以äžã®èŠçŽ ãèæ ®ããŠãã ããïŒ
- ããŒã¿æ€èšŒãšããŒã«ãªãŒãŒã·ã§ã³ïŒ ããŒã¿æ€èšŒã«ãŒã«ãç°ãªããã±ãŒã«ã«å¯ŸããŠé©åã§ããããšã確èªããŸããäŸãã°ãæ¥ä»ãæ°å€ã®åœ¢åŒã¯åœã«ãã£ãŠç°ãªããŸããããŒã«ãªãŒãŒã·ã§ã³ãµããŒãã®ããã« `babel` ã®ãããªã©ã€ãã©ãªã®äœ¿çšãæ€èšããŠãã ããã
- é貚ã®åãæ±ãïŒ ééçãªå€ãæ±ãå Žåã¯ã`moneyed` ã®ãããªã©ã€ãã©ãªã䜿çšããŠãç°ãªãé貚ãçºæ¿ã¬ãŒããæ£ããåŠçããŸãã
- ã¿ã€ã ãŸãŒã³ïŒ æ¥ä»ãšæå»ãæ±ãéã¯ãã¿ã€ã ãŸãŒã³ã«æ³šæãã`pytz` ã®ãããªã©ã€ãã©ãªã䜿çšããŠã¿ã€ã ãŸãŒã³å€æãåŠçããŸãã
- æåãšã³ã³ãŒãã£ã³ã°ïŒ ç¹ã«ããã¹ãããŒã¿ãæ±ãå Žåãã³ãŒããç°ãªãæåãšã³ã³ãŒãã£ã³ã°ãæ£ããåŠçããããšã確èªããŸããUTF-8ã¯åºããµããŒããããŠãããšã³ã³ãŒãã£ã³ã°ã§ãã
ãã¹ã¯ãªãã¿ã®ä»£æ¿æ¡
ãã¹ã¯ãªãã¿ã¯åŒ·åã§ãããåžžã«æè¯ã®è§£æ±ºçãšã¯éããŸããã以äžã«ããã€ãã®ä»£æ¿æ¡ãæããŸãïŒ
- `property()`: åçŽãªã²ãã¿ãŒ/ã»ãã¿ãŒããžãã¯ã«ã¯ã`property()` 颿°ãããç°¡æœãªæ§æãæäŸããŸãã
- `__slots__`: ã¡ã¢ãªäœ¿çšéãåæžããåçãªå±æ§äœæãé²ãããå Žå㯠`__slots__` ã䜿çšããŸãã
- æ€èšŒã©ã€ãã©ãªïŒ `marshmallow` ã®ãããªã©ã€ãã©ãªã¯ãããŒã¿æ§é ãå®çŸ©ãæ€èšŒããããã®å®£èšçãªæ¹æ³ãæäŸããŸãã
- ããŒã¿ã¯ã©ã¹ïŒ Python 3.7以éã®ããŒã¿ã¯ã©ã¹ã¯ã`__init__`ã`__repr__`ã`__eq__` ã®ãããªã¡ãœãããèªåçæãããã¯ã©ã¹ãç°¡æœã«å®çŸ©ããæ¹æ³ãæäŸããŸããããŒã¿æ€èšŒã®ããã«ãã¹ã¯ãªãã¿ãæ€èšŒã©ã€ãã©ãªãšçµã¿åãããããšãã§ããŸãã
çµè«
Pythonã®ãã¹ã¯ãªãã¿ãããã³ã«ã¯ãã¯ã©ã¹ã®å±æ§ã¢ã¯ã»ã¹ãšããŒã¿æ€èšŒã管çããããã®è²ŽéãªããŒã«ã§ãããã®äžå¿çãªæŠå¿µãšãã¹ããã©ã¯ãã£ã¹ãçè§£ããããšã§ãããã¯ãªãŒã³ã§å ç¢ããã€ä¿å®æ§ã®é«ãã³ãŒããæžãããšãã§ããŸãããã¹ãŠã®å±æ§ã«ãã¹ã¯ãªãã¿ãå¿ èŠãªããã§ã¯ãããŸããããããããã£ã¢ã¯ã»ã¹ãšããŒã¿ã®æŽåæ§ã«å¯Ÿãããã现ããå¶åŸ¡ãå¿ èŠãªå Žåã«ã¯äžå¯æ¬ ã§ãããã¹ã¯ãªãã¿ã®å©ç¹ãšæœåšçãªãªãŒããŒããããæ¯èŒæ€èšããé©åãªå Žåã«ã¯ä»£æ¿ã¢ãããŒããæ€èšããããšãå¿ããªãã§ãã ããããã¹ã¯ãªãã¿ã®åãæŽ»çšããŠãPythonããã°ã©ãã³ã°ã¹ãã«ãåäžãããããæŽç·Žãããã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŸãããã